ACM/ICPC 之 最短路径-dijkstra范例(ZOJ2750-POJ1135(ZOJ1298))
最短路经典算法-dijkstra范例(两道),第一道是裸的dijkstra,第二道需要枚举所有边已找到可能的情况。
ZOJ2750-Idiomatic Phrases Game
题意:见Code
题解:dijkstra算法需要理解的是松弛操作,这一点掌握好了,其他的代码书写则有点类似于Prim算法,易于掌握。
本题需要记录每一个成语的前4个字符和后4个字符以记录成语的第一个字和最后一个字,博主省略了建图的过程,直接重载了Idiom结构体的“==”运算符,在dijkstra也直接使用了该判断,经过分析可以知道这种算法和利用邻接矩阵建图后再进行dijkstra的算法时间度基本一致O(n^2),因此权当简化代码也好。
1 //成语接龙-dijkstra 2 //求从第一个成语道最后一个成语最短耗时(第一个列数据为T,表示需要耗时T后才能接龙下一个成语) 3 //Time:50Ms Memory:292K 4 #include<iostream> 5 #include<cstring> 6 #include<cstdio> 7 #include<vector> 8 #include<algorithm> 9 using namespace std; 10 11 #define MAX 1001 12 #define INF 0x3f3f3f3f 13 14 struct Idiom { 15 int time; 16 char pre[5], rear[5]; 17 friend bool operator == (Idiom id1, Idiom id2) { return !strcmp(id1.rear, id2.pre); } 18 }idiom[MAX]; 19 20 int n; 21 int d[MAX], mintime; //mintime:最短路耗时 22 bool v[MAX]; 23 24 void dijkstra() 25 { 26 memset(v, false, sizeof(v)); 27 memset(d, INF, sizeof(d)); 28 v[0] = true; 29 mintime = -1; //默认失败 30 for (int i = 1; i < n; i++) 31 { 32 if (idiom[0] == idiom[i]) 33 d[i] = idiom[0].time; 34 } 35 for (int i = 1; i < n; i++) 36 { 37 int mind = INF; 38 int k; 39 for (int j = 1; j < n;j++) 40 { 41 if (!v[j] && mind > d[j]) 42 { 43 mind = d[j]; 44 k = j; 45 } 46 } 47 48 if (mind == INF) return; //失败 49 if (k == n - 1) { //成功 50 mintime = d[k]; 51 return; 52 } 53 v[k] = true; 54 for (int j = 1; j < n; j++) 55 if (!v[j] && idiom[k] == idiom[j]) d[j] = min(d[k] + idiom[k].time, d[j]); 56 } 57 } 58 59 int main() 60 { 61 while (scanf("%d", &n), n) 62 { 63 char str[25]; 64 for (int i = 0; i < n; i++) 65 { 66 scanf("%d%s", &idiom[i].time, str); 67 int len = strlen(str); 68 for (int j = 0; j < 4; j++) 69 { 70 idiom[i].pre[j] = str[j]; 71 idiom[i].rear[j] = str[len - 4 + j]; 72 } 73 idiom[i].pre[4] = idiom[i].rear[4] = '\0'; 74 } 75 76 dijkstra(); 77 printf("%d\n", mintime); 78 } 79 80 return 0; 81 }
POJ1135(ZOJ1298)-Domino Effect
题意及题解:见Code注释部分
1 //求从1开始倒下的多米诺骨牌最后倒下的时间及在何处倒下(在两个关键牌中间倒下则输出两个关键牌) 2 //dijkstra计算最短路,而后枚举每一条边上的时间(不一定在最短路的最大时间点和次大时间点内),以计算最后倒下的时间 3 //Time:32Ms Memory:1176K 4 #include<iostream> 5 #include<cstring> 6 #include<cstdio> 7 #include<algorithm> 8 using namespace std; 9 10 #define MAX 505 11 #define INF 0x3f3f3f3f 12 13 int n, m; 14 int map[MAX][MAX]; //如果MAX达10^4以上,考虑用邻接表 15 int d[MAX]; 16 bool v[MAX]; 17 int pos; //关键牌编号 18 double maxtime; //关键牌最后倒下的时间 19 20 void dijkstra() 21 { 22 memset(v, false, sizeof(v)); 23 memset(d, 0, sizeof(d)); 24 pos = 1; //默认 25 maxtime = 0; 26 v[1] = true; 27 for (int i = 2; i <= n; i++) 28 d[i] = map[i][1]; 29 for (int i = 2; i <= n; i++) 30 { 31 int mind = INF; 32 int k = 0; 33 for (int j = 2; j <= n; j++) 34 { 35 if (!v[j] && mind > d[j]) 36 { 37 mind = d[j]; 38 k = j; 39 } 40 } 41 42 maxtime = mind; 43 pos = k; 44 v[k] = true; 45 for (int j = 2; j <= n; j++) //松弛 46 if (!v[j]) d[j] = min(d[k] + map[k][j], d[j]); 47 } 48 49 } 50 int main() 51 { 52 int cas = 0; 53 while (scanf("%d%d", &n, &m), n || m) 54 { 55 memset(map, INF, sizeof(map)); 56 for (int i = 0; i < m; i++) 57 { 58 int u, v, w; 59 scanf("%d%d%d", &u, &v, &w); 60 map[u][v] = map[v][u] = w; 61 } 62 dijkstra(); 63 64 printf("System #%d\n", ++cas); 65 bool flag = false; //存在关键牌外的牌倒下时间更多的情况 66 int pos1, pos2; 67 for (int i = 1; i <= n; i++) 68 for (int j = i + 1; j <= n; j++) 69 { 70 if (map[i][j] != INF && (d[i] + d[j] + map[i][j]) / 2.0 > maxtime) 71 { 72 maxtime = (d[i] + d[j] + map[i][j]) / 2.0; 73 pos1 = i; pos2 = j; 74 flag = true; 75 } 76 } 77 78 if (flag) 79 printf("The last domino falls after %.1f seconds, between key dominoes %d and %d.\n\n", maxtime, pos1, pos2); 80 else printf("The last domino falls after %.1f seconds, at key domino %d.\n\n", maxtime, pos); 81 } 82 return 0; 83 }
他坐在湖边,望向天空,她坐在对岸,盯着湖面